#region Copyright
//	Copyright (c) 2007 eBay, Inc.
//
//	This program is licensed under the terms of the eBay Common Development and 
//	Distribution License (CDDL) Version 1.0 (the "License") and any subsequent 
//	version thereof released by eBay.  The then-current version of the License 
//	can be found at https://www.codebase.ebay.com/Licenses.html and in the 
//	eBaySDKLicense file that is under the eBay SDK install directory.
#endregion

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using eBay.Service.Call;
using eBay.Service.Core.Sdk;
using eBay.Service.Core.Soap;
using eBay.Service.Util;

namespace GetItemTester
{

    public class eBayApi
    {

        #region private fields

        private static string sSoapApiUrl = LoadAppConfig("Environment.ApiServerUrl");
        private static Form1 app;
        private static string token;
        private static ApiContext ctx;
        private static Mutex mCtx = new Mutex();
        private static CallRetry retry;
        private static Mutex mRetry = new Mutex();
        private static ApiLogger logger;
        private static string currentUser;

        private static int MaxRetry = Convert.ToInt32(LoadAppConfig("MaxRetry"));
        private static readonly object LockRoot = new object();


        #endregion

        #region constructor

        private eBayApi() { }

        #endregion

        #region static public method

        public static void Init(Form1 app, string currentUser, string token, ApiLogger logger)
        {
            eBayApi.app = app;
            eBayApi.token = token;
            eBayApi.logger = logger;
            eBayApi.currentUser = currentUser;
        }



        /// <summary>
        /// add an item
        /// </summary>
        /// <returns></returns>
        public static string AddItem(CallMetricsTable metrics)
        {
            try
            {
                ApiContext ctx = GetContext();
                ctx.EnableMetrics = true;
                ctx.CallMetricsTable = metrics;
                AddItemCall call = new AddItemCall(ctx);
                call.Site = SiteCodeType.US;
                // call.Item = ItemHelper.BuildItem();
                call.Execute();


                return CheckForErrors("AddItem", call) ?
                call.ApiResponse.ItemID : null;
            }
            catch (Exception e)
            {
                ShowException("AddItem()", e);
                return null;
            }
        }

        public static string GetItem(string itemId, string tokekn)
        {
            try
            {
                ApiContext ctx = GetContext(tokekn, "angelcitiz2011");
             //   ctx.EnableMetrics = true;
               // ctx.CallMetricsTable = metrics;
                GetItemCall call = new GetItemCall(ctx);
                call.Site = SiteCodeType.US;
                call.IncludeItemSpecifics = true;
                call.DetailLevelList = new DetailLevelCodeTypeCollection() {DetailLevelCodeType.ItemReturnAttributes};
                call.ItemID = itemId;
     
                // call.Item = ItemHelper.BuildItem();
                call.Execute();


                return CheckForErrors("AddItem", call) ?
                call.ApiResponse.Item.ItemID : null;
            }
            catch (Exception e)
            {
                ShowException("AddItem()", e);
                return null;
            }
        }


        public static void GetCategorySpecifics( string tokekn)
        {
            try
            {
                ApiContext ctx = GetContext(tokekn, "angelcitiz2011");
                //   ctx.EnableMetrics = true;
                // ctx.CallMetricsTable = metrics;
                GetCategorySpecificsCall call = new GetCategorySpecificsCall(ctx);
                call.Site = SiteCodeType.US;
   
                call.DetailLevelList = new DetailLevelCodeTypeCollection() { DetailLevelCodeType.ItemReturnAttributes };
                call.CategoryIDList = new StringCollection() {"9355"};

                // call.Item = ItemHelper.BuildItem();
                var result= call.GetCategorySpecifics(new StringCollection() { "9355" });


        
            }
            catch (Exception e)
            {
                ShowException("AddItem()", e);
              
            }
        }

        /// <summary>
        /// get context
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static ApiContext GetEmptyContext(string token, string ebayUser)
        {


            return GetContext(string.Empty, ebayUser);
        }


        public static ApiContext GetContext(string token, string ebayUser)
        {
            ApiContext context = new ApiContext();

            context.ApiCredential.ApiAccount.Application = LoadAppConfig("Environment.AppId");
            context.ApiCredential.ApiAccount.Developer = LoadAppConfig("Environment.DevId");
            context.ApiCredential.ApiAccount.Certificate = LoadAppConfig("Environment.CertId");
            context.ApiCredential.eBayToken = token;// LoadAppConfig(token);
            context.SoapApiServerUrl = LoadAppConfig("Environment.ApiServerUrl");
            context.SignInUrl = LoadAppConfig("Environment.SignInUrl");
            context.RuName = LoadAppConfig("RunName");

            context.ApiCredential.eBayAccount = new eBayAccount();
            context.ApiCredential.eBayAccount.UserName = ebayUser;
            context.EPSServerUrl = LoadAppConfig("Environment.EpsServerUrl");
            context.Version = LoadAppConfig("Version");
            context.Timeout = Convert.ToInt32(LoadAppConfig("TimeOut"));
            context.Site = SiteCodeType.US;

            ApiLogManager Logger = new ApiLogManager();
            Logger.EnableLogging = Convert.ToBoolean(LoadAppConfig("LoggingEnabled"));
            if (Logger.EnableLogging)
            {
                string logfile = LoadAppConfig("logfile");
                if (!string.IsNullOrEmpty(logfile))
                {

                    Logger.ApiLoggerList.Add(new FileLogger(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logfile)));

                    if (LoadAppConfig("logexception").ToUpper() == "TRUE")
                        Logger.ApiLoggerList[0].LogExceptions = true;

                    if (LoadAppConfig("logmessages").ToUpper() == "TRUE")
                        Logger.ApiLoggerList[0].LogApiMessages = true;
                    Logger.ApiLoggerList[0].LogInformations = true;

                }
            }
            context.ApiLogManager = Logger;
            context.CallRetry = GetCallRetry();
            return context;
        }


        public static string GetSessionId(ApiContext context, string ruName)
        {
            return new GetSessionIDCall(context).GetSessionID(ruName);
        }

        public static string LaunchSignInPage(ApiContext context, string sessionID)
        {
            if (context == null)
                throw new SdkException("Please specify the Context.", new System.ArgumentNullException());

            if (string.IsNullOrEmpty(context.SignInUrl))
                throw new SdkException("Please specify the SignInUrl in the Context object.", new System.ArgumentNullException());

            if (string.IsNullOrEmpty(context.RuName))
                throw new SdkException("Please specify a RuName.", new System.ArgumentNullException());

            // Go to the page.
            string finalUrl = context.SignInUrl + "&runame=" + context.RuName;
            if (!string.IsNullOrEmpty(sessionID))
                finalUrl += "&sessid=" + sessionID;

            return finalUrl;
        }

        #endregion

        #region private static method

        private static ApiContext GetContext()
        {
            if (ctx != null)
                return ctx;

            Debug.Assert(token.Length > 0);

            try
            {
                mCtx.WaitOne();
                if (ctx != null)
                    return ctx;

                ctx = GetContext(token, string.Empty);
                return ctx;
            }
            finally
            {
                mCtx.ReleaseMutex();
            }
        }


        private static CallRetry GetCallRetry()
        {
            if (retry != null)
                return retry;

            try
            {
                mRetry.WaitOne();
                if (retry != null)
                    return retry;

                retry = new CallRetry();
                retry.DelayTime = 1000;		// 1 second
                retry.MaximumRetries = 2;
                // retry.TriggerErrorCodes
                // retry.TriggerExceptions
                return retry;
            }
            finally
            {
                mRetry.ReleaseMutex();
            }
        }

        private static bool CheckForErrors(string function, ApiCall call)
        {
            // Warning out to not get Schema Out Of Date messages
            if (call.HasError /*|| call.HasWarning */)
            {
                ApiException exc = call.ApiException;
                Debug.Assert(exc != null);
                StringBuilder sb = new StringBuilder(function);
                sb.Append(":\n");
                foreach (ErrorType err in exc.Errors)
                {
                    sb.AppendFormat("message: {0}, details: {1}\n",
                        err.ShortMessage, err.LongMessage);
                }

                ShowMessage(sb.ToString());
            }

            return !call.HasError;
        }

        private static void ShowException(string function, Exception e)
        {
            StringBuilder sbInfo = new StringBuilder();
            if (e is ApiException)
            {
                ApiException exc = e as ApiException;
                foreach (ErrorType err in exc.Errors)
                {
                    sbInfo.AppendFormat("message: {0}, details: {1}\n",
                        err.ShortMessage, err.LongMessage);
                }
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0}: caught {1}\n", function,
                e.GetType().ToString());
            if (sbInfo.Length > 0)
                sb.AppendFormat("Info: {0}", sbInfo.ToString());
            sb.AppendFormat("Exception: {0}\n", e.ToString());
            /*
            if (e.InnerException != null)
                sb.AppendFormat("InnerException: {0}",
                    e.InnerException.ToString());
            */
            ShowMessage(sb.ToString());
        }


        public static string LoadAppConfig(string key)
        {
            return ConfigurationManager.AppSettings.Get(key);
        }



        public static void log(string msg)
        {
            logger.RecordMessage(msg, MessageSeverity.Informational);
        }

        private static void ShowMessage(string msg)
        {
            log(msg);
        }

        #endregion

        #region delegate

        private delegate void ShowMessageDelegate(string msg);

        #endregion


        public static string UploadPictures(KeyValuePair<string, string> picture)
        {

            //read the image file as a byte array

            FileStream fs = new FileStream(picture.Value, FileMode.Open, FileAccess.Read);
            fs.Seek(0, SeekOrigin.Begin);
            BinaryReader br = new BinaryReader(fs);

            byte[] image = br.ReadBytes((int)fs.Length);

            br.Close();

            fs.Close();


            HttpWebResponse resp;


            HttpWebRequest currentRequest = (HttpWebRequest)WebRequest.Create(LoadAppConfig("Environment.EpsServerUrl"));


            string boundary = "MIME_boundary";

            string CRLF = "\r\n";


            //Add the request headers

            currentRequest.Headers.Add("X-EBAY-API-COMPATIBILITY-LEVEL", LoadAppConfig("Version"));

            currentRequest.Headers.Add("X-EBAY-API-DEV-NAME", LoadAppConfig("Environment.DevId")); //use your devid

            currentRequest.Headers.Add("X-EBAY-API-APP-NAME", LoadAppConfig("Environment.AppId")); //use your appid

            currentRequest.Headers.Add("X-EBAY-API-CERT-NAME", LoadAppConfig("Environment.CertId")); //use your certid

            currentRequest.Headers.Add("X-EBAY-API-SITEID", LoadAppConfig("UserAccount.eBayUserSiteId"));

            currentRequest.Headers.Add("X-EBAY-API-DETAIL-LEVEL", "0");

            currentRequest.Headers.Add("X-EBAY-API-CALL-NAME", "UploadSiteHostedPictures");

            currentRequest.ContentType = "multipart/form-data; boundary=" + boundary;


            //set the method to POST

            currentRequest.Method = "POST";

            //set the HTTP version to 1.0

            currentRequest.ProtocolVersion = HttpVersion.Version10;


            //replace token with your own token

            string token = LoadAppConfig("UserAccount.ApiToken");


            //Construct the request
            string strReq1 = "--" + boundary + CRLF
                             + "Content-Disposition: form-data; name=document" + CRLF
                             + "Content-Type: text/xml; charset=\"UTF-8\"" + CRLF + CRLF
                             + "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                             + "<UploadSiteHostedPicturesRequest xmlns=\"urn:ebay:apis:eBLBaseComponents\">"
                             + "<PictureSet>Supersize</PictureSet>"
                             + "<RequesterCredentials>"
                             + "<eBayAuthToken>" + token + "</eBayAuthToken>"
                             + "</RequesterCredentials>"
                             + "</UploadSiteHostedPicturesRequest>"
                             + CRLF + "--" + boundary + CRLF
                             + "Content-Disposition: form-data; name=image; filename=image" + CRLF
                             + "Content-Type: application/octet-stream" + CRLF
                             + "Content-Transfer-Encoding: binary" + CRLF + CRLF;

            string strReq2 = CRLF + "--" + boundary + "--" + CRLF;

            //Convert the string to a byte array
            byte[] postDataBytes1 = Encoding.ASCII.GetBytes(strReq1);
            byte[] postDataBytes2 = Encoding.ASCII.GetBytes(strReq2);


            int len = postDataBytes1.Length + postDataBytes2.Length + image.Length;
            currentRequest.ContentLength = len;

            //Post the request to eBay
            Stream requestStream = currentRequest.GetRequestStream();
            requestStream.Write(postDataBytes1, 0, postDataBytes1.Length);
            requestStream.Write(image, 0, image.Length);
            requestStream.Write(postDataBytes2, 0, postDataBytes2.Length);
            requestStream.Close();



            string response;

            int nRetry = 0;


            while (nRetry < MaxRetry)
            {
                try
                {
                    // get response and write to console

                    resp = (HttpWebResponse)currentRequest.GetResponse();

                    StreamReader responseReader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8);

                    response = responseReader.ReadToEnd();

                    resp.Close();



                    //response contains our pictures url

                    XmlDocument xml = new XmlDocument();

                    xml.LoadXml(response);



                    //Extract the FullURL from the response

                    XmlNodeList list = xml.GetElementsByTagName("FullURL", "urn:ebay:apis:eBLBaseComponents");


                    return list[0].InnerText;

                }

                catch (Exception ex)
                {
                    nRetry++;

                }
                //Get the other elements from the response if required
            }

            return string.Empty;
        }


    }
}
